import "@xyflow/react/dist/style.css";
import { useQuery } from "@tanstack/react-query";
import {
  applyEdgeChanges,
  applyNodeChanges,
  Background,
  Controls,
  Edge,
  EdgeChange,
  Node,
  NodeChange,
  ReactFlow
} from "@xyflow/react";
import * as d3 from "d3-force";
import { Loader } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";

import * as srv from "@/services";

import { GraphEdge } from "./Edge";
import { GraphNode } from "./Node";
import { SidebarInset, SidebarTrigger } from "@/components/ui/sidebar";

const nodesTypes = {
  graph: GraphNode
};

const edgeTypes = {
  graph: GraphEdge
};

export function DocGraph() {
  const [nodes, setNodes] = useState<Node[]>([]);
  const [edges, setEdges] = useState<Edge[]>([]);
  const simulationTickEnd = useRef(false);

  const { data: pages = [] } = useQuery({
    queryKey: ["pageGraph"],
    queryFn: async () => {
      return (await srv.fetchPageGraph()).data;
    }
  });

  // 简单检查重复 pageId
  useEffect(() => {
    if (!pages.length) return;
    const pageIds = pages.map(p => p.pageId);
    const uniquePageIds = new Set(pageIds);
    if (pageIds.length !== uniquePageIds.size) {
      console.warn("警告：pages 中存在重复的 pageId！", pageIds);
    }
  }, [pages]);

  const handleNodeClick = (_: React.MouseEvent, node: Node) => {
    const { id } = node;
    setNodes(nds => nds.map(n => ({ ...n, selected: n.id === id })));
    setEdges(eds => eds.map(e => ({ ...e, selected: e.source === id || e.target === id })));
  };

  const onNodesChange = useCallback((changes: NodeChange[]) => setNodes(nds => applyNodeChanges(changes, nds)), []);
  const onEdgesChange = useCallback((changes: EdgeChange[]) => setEdges(eds => applyEdgeChanges(changes, eds)), []);

  useEffect(() => {
    if (!pages.length) return;

    // 1. 生成初始节点（ReactFlow 需要 position）
    const initialNodes: Node[] = pages.map(page => ({
      id: page.pageId,
      type: "graph",
      data: {
        emoji: page.emoji,
        title: page.title
      },
      width: 100,
      height: 100,
      position: { x: 0, y: 0 }
    }));

    // 2. 生成 edges（ReactFlow 用的版本：保持 source/target 纯字符串）
    const edgeIdSet = new Set<string>();
    const flowEdges: Edge[] = pages.flatMap(
      page =>
        (page.links || [])
          .filter(link => pages.some(p => p.pageId === link))
          .map(link => {
            const id = `${page.pageId}-${link}`;
            if (edgeIdSet.has(id)) return null; // 去重
            edgeIdSet.add(id);
            return {
              id,
              source: page.pageId,
              target: link,
              type: "graph"
            };
          })
          .filter(Boolean) as Edge[]
    );

    // 3. d3-force 用的 edges（可被它改动）
    const d3Edges = flowEdges.map(e => ({ ...e }));

    // 4. d3-force 布局
    const simulation = d3
      .forceSimulation(initialNodes)
      .force("charge", d3.forceManyBody().strength(-50))
      .force("collide", d3.forceCollide(80))
      .force(
        "link",
        d3
          .forceLink(d3Edges)
          .id((d: any) => d.id)
          .strength(1)
          .distance(200)
          .iterations(100)
      )
      .force("center", d3.forceCenter(700, 400))
      .force("radial", d3.forceRadial(0, 700, 400));

    simulation.on("end", () => {
      simulationTickEnd.current = true;
    });

    simulation.on("tick", () => {
      const forceNodes = simulation.nodes().map(node => ({
        ...node,
        position: { x: node.x || 0, y: node.y || 0 }
      }));
      setNodes(forceNodes);
    });

    // 把 ReactFlow 用的 edges 存进去（它不会被 d3 改）
    setEdges(flowEdges);

    return () => {
      simulation.stop();
    };
  }, [pages]);

  return (
    <SidebarInset>
      <div className="flex flex-col w-full h-full">
        <div className="flex flex-row items-center p-6 gap-2">
          <SidebarTrigger />
          <h1 className="text-xl text-zinc-500">文档图谱</h1>
        </div>
        <div className="w-full h-full relative">
          {!simulationTickEnd.current && (
            <div className="w-full h-full flex justify-center items-center bg-zinc-50 opacity-30 absolute z-10">
              <div className="flex flex-col items-center gap-2">
                <Loader className="w-8 h-8 animate-spin" />
                <p className="text-sm">加载中...</p>
              </div>
            </div>
          )}
          <ReactFlow
            nodesDraggable
            proOptions={{
              hideAttribution: true
            }}
            nodes={nodes}
            edges={edges}
            nodeTypes={nodesTypes}
            edgeTypes={edgeTypes}
            onNodeClick={handleNodeClick}
            onNodeDragStart={handleNodeClick}
            onNodesChange={onNodesChange}
            onEdgesChange={onEdgesChange}
          >
            <Background />
            <Controls />
          </ReactFlow>
        </div>
      </div>
    </SidebarInset>
  );
}
